// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/lib/base/hardened.h"
#include "sw/device/lib/base/status.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/entropy_testutils.h"
#include "sw/device/lib/testing/hexstr.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/silicon_creator/lib/ownership/ecdsa.h"
#include "sw/device/silicon_creator/lib/ownership/keys/fake/no_owner_recovery_ecdsa_p256.h"

// From: http://www.abrahamlincolnonline.org/lincoln/speeches/gettysburg.htm
static const char kGettysburgPrelude[] =
    "Four score and seven years ago our fathers brought forth on this "
    "continent, a new nation, conceived in Liberty, and dedicated to the "
    "proposition that all men are created equal.";

// clang-format off
/*
 * This signature was generated by signing the sha256sum of the prelude to
 * Lincoln's Gettysburg Address with the fake "no owner recovery key".
 *
 $ echo -n "Four score and seven years ago our fathers brought forth on this\
 continent, a new nation, conceived in Liberty, and dedicated to the\
 proposition that all men are created equal." | sha256sum -

 1e6fd4030f9034cd775708a396c324ed420ec587eb3dd433e29f6ac08b8cc7ba  -

 $ opentitantool ecdsa sign \
    sw/device/silicon_creator/rom_ext/keys/fake/ownership_no_owner_recovery_ecdsa_p256.der \
    0x1e6fd4030f9034cd775708a396c324ed420ec587eb3dd433e29f6ac08b8cc7ba

{
  digest: "bac78c8bc06a9fe233d43deb87c50e42ed24c396a3085777cd34900f03d46f1e",
  signature: "cda24f37d4979cea1446c495af344af83d2047d13191b41003431a182bf2b74c365b08b78c57e3c3c11960fbc4a53fb63f61aecba3ddbda00059aebd08ad8f2c"
}

 *
 * The `digest` and `signature` string were copied verbatim into this test.
 */
// This is the little-endian representation of the Gettysburg SHA256 digest.
static const char kGettysburgDigest[] =
    "bac78c8bc06a9fe233d43deb87c50e42ed24c396a3085777cd34900f03d46f1e";

static const char kGettysburgSignature[] =
    "cda24f37d4979cea1446c495af344af83d2047d13191b41003431a182bf2b74c"
    "365b08b78c57e3c3c11960fbc4a53fb63f61aecba3ddbda00059aebd08ad8f2c";
// clang-format on

static const owner_key_t kNoOwnerRecoveryKey = NO_OWNER_RECOVERY_ECDSA_P256;

void __assert_func(const char *file, int line, const char *func,
                   const char *expr) {
  LOG_ERROR("%s:%d: %s %s", file, line, func, expr);
  abort();
}

static status_t initialize(void) {
  TRY(ecdsa_init());
  return OK_STATUS();
}

// Tests that we can verify an ECDSA signature given the digest.
status_t ecdsa_verify_digest_test(void) {
  hmac_digest_t digest;
  TRY(hexstr_decode(&digest, sizeof(digest), kGettysburgDigest));
  owner_signature_t signature;
  TRY(hexstr_decode(&signature.ecdsa, sizeof(signature.ecdsa),
                    kGettysburgSignature));
  hardened_bool_t result = ecdsa_verify_digest(&kNoOwnerRecoveryKey.ecdsa,
                                               &signature.ecdsa, &digest);
  TRY_CHECK(result == kHardenedBoolTrue);
  return OK_STATUS();
}

// Tests that we can verify an ECDSA signature of a message.
// The message is first sha256-hashed to a digest and then verified.
status_t ecdsa_verify_message_test(void) {
  owner_signature_t signature;
  TRY(hexstr_decode(&signature.ecdsa, sizeof(signature.ecdsa),
                    kGettysburgSignature));
  hardened_bool_t result =
      ecdsa_verify_message(&kNoOwnerRecoveryKey.ecdsa, &signature.ecdsa,
                           kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
  TRY_CHECK(result == kHardenedBoolTrue);
  return OK_STATUS();
}

OTTF_DEFINE_TEST_CONFIG();

bool test_main(void) {
  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
  status_t result = initialize();
  EXECUTE_TEST(result, ecdsa_verify_digest_test);
  EXECUTE_TEST(result, ecdsa_verify_message_test);
  return status_ok(result);
}
